package cn.mrcode.wxsdk.core.dialogue.common.accessToken.lifeCycle.distributed;


import cn.mrcode.wxsdk.core.dialogue.common.PublicAccount;
import cn.mrcode.wxsdk.core.dialogue.common.accessToken.lifeCycle.IAccessTokenService;
import cn.mrcode.wxsdk.core.dialogue.common.accessToken.lifeCycle.distributed.strategy.master.AccessTokenDistributedTaskMaster;
import cn.mrcode.wxsdk.core.dialogue.common.accessToken.lifeCycle.distributed.strategy.master_old.ZkAccessToken;
import cn.mrcode.wxsdk.core.dialogue.protocol.base.AccessTokenInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * AccessToken 生命周期维护,单机版
 * @author zhuqiang
 * @version V1.0
 * @date 2015/9/22 15:25
 */
public class AccessTokenDistributedService implements IAccessTokenService {
    private static Logger log = LoggerFactory.getLogger(AccessTokenDistributedService.class);

    private static final ConcurrentHashMap<String, AccessTokenInfo> accessTokenMap = new ConcurrentHashMap<String, AccessTokenInfo>();
    private static AccessTokenDistributedService instance;

    private AccessTokenDistributedService() {
    }

    private static ReentrantLock lock = new ReentrantLock();

    @Deprecated
    public static AccessTokenDistributedService getInstance(int sessionTimeout, String zkServiceList, String rootPath, HashMap<String, PublicAccount> accountMap) {
        lock.lock();
        try {
            if (instance == null) {
                instance = new AccessTokenDistributedService();
                ZkAccessToken zt = new ZkAccessToken(sessionTimeout, zkServiceList, rootPath,accessTokenMap,accountMap);
                zt.init();
//                log.debug("分布式基础支持token已被初始化ZkAccessToken");
            }
        } finally {
            lock.unlock();
        }
        return instance;
    }

    /**
     * curator 实现的服务
     * @param sessionTimeout
     * @param zkServiceList
     * @param accountMap
     * @return
     */
    public static AccessTokenDistributedService getInstance(int sessionTimeout, String zkServiceList, HashMap<String, PublicAccount> accountMap) {
        lock.lock();
        try {
            if (instance == null) {
                instance = new AccessTokenDistributedService();
                new AccessTokenDistributedTaskMaster(sessionTimeout,zkServiceList,accountMap,accessTokenMap).init();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return instance;
    }


    @Override
    public String getAccesstoken(String appid, String secret) throws Exception {
        AccessTokenInfo ati = accessTokenMap.get(appid);
        int i = 0;
        while (ati == null) {
            if (i == 10) {
                log.error("获取token失败,本地没有可用token");
                throw new Exception("获取token失败,本地没有可用token");
            }
            log.debug("本地项目中没有appId为:" + appid + " 可用的token，第 " + (++i) + " 次尝试获取token后将休眠500毫秒后再次获取。本地可用token数量为：" + accessTokenMap.size());
            TimeUnit.MILLISECONDS.sleep(500); //为空则休眠n毫秒再获取
            ati = accessTokenMap.get(appid);
        }

        if(ati ==  null){
            log.error("发生了一个致命错误：在尝试了10次(共5秒)后还是没有获取到可用token");
        }

        return ati.getAccessToken();
    }
}
